package com.jshcbd.mvp_kt_demo.utils;


import androidx.annotation.NonNull;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class ArrayUtils {

    public static <T> boolean isEmpty(T[] arrays) {
        return arrays == null || arrays.length == 0;
    }

    public static <T> boolean isEmpty(Collection<T> list) {
        return list == null || list.size() == 0;
    }

    public static <T> Collection<T> filter(@NonNull Collection<T> target, Filter<T> predicate) {
        ArrayList<T> result = new ArrayList<>();
        for (T element : target) {
            if (predicate.accept(element)) {
                result.add(element);
            }
        }
        return result;
    }

    public static <T> boolean contains(Collection<T> list, T item) {
        if (isEmpty(list)) {
            return false;
        }
        for (T t : list) {
            if (t.equals(item)) {
                return true;
            }
        }
        return false;
    }

    public static <T> boolean contains(T[] list, T item) {
        return contains(Arrays.asList(list), item);
    }

    public static <T> T getFromList(T[] list, T item) {
        if (!contains(list, item)) {
            return null;
        }
        for (T t : list) {
            if (t.equals(item)) {
                return t;
            }
        }
        return null;
    }

    public static <T> boolean equals(List<T> array0, List<T> array1) {
        if (array0 == array1 || (ArrayUtils.isEmpty(array0) && ArrayUtils.isEmpty(array1))) {
            return true;
        }
        if ((ArrayUtils.isEmpty(array0) && !ArrayUtils.isEmpty(array1))
                || (!ArrayUtils.isEmpty(array0) && ArrayUtils.isEmpty(array1))) {
            return false;
        }
        if (array0.size() != array1.size()) {
            return false;
        }
        for (int i = 0; i < array0.size(); i++) {
            if (!array0.get(i).equals(array1.get(i))) {
                return false;
            }
        }
        return true;
    }

    public static <T> boolean equals(T[] array0, T[] array1) {
        if (array0 == array1 || (ArrayUtils.isEmpty(array0) && ArrayUtils.isEmpty(array1))) {
            return true;
        }
        if ((ArrayUtils.isEmpty(array0) && !ArrayUtils.isEmpty(array1))
                || (!ArrayUtils.isEmpty(array0) && ArrayUtils.isEmpty(array1))) {
            return false;
        }
        if (array0.length != array1.length) {
            return false;
        }
        for (int i = 0; i < array0.length; i++) {
            if (!array0[i].equals(array1[i])) {
                return false;
            }
        }
        return true;
    }

    public static <T> boolean equals(T[] array0, T[] array1, Comparator<T> comparator) {
        if (array0 == array1 || (ArrayUtils.isEmpty(array0) && ArrayUtils.isEmpty(array1))) {
            return true;
        }
        if ((ArrayUtils.isEmpty(array0) && !ArrayUtils.isEmpty(array1))
                || (!ArrayUtils.isEmpty(array0) && ArrayUtils.isEmpty(array1))) {
            return false;
        }
        if (array0.length != array1.length) {
            return false;
        }
        for (int i = 0; i < array0.length; i++) {
            if (comparator.compare(array0[i], array1[i]) != 0) {
                return false;
            }
        }
        return true;
    }

    /**
     * @param from the initial index of the range to be copied, inclusive
     * @param to   the final index of the range to be copied, exclusive.
     */
    public static <T, U> T[] copyOfRange(U[] original, int from, int to, Class<? extends T[]> newType, CopyArrayConvert<U, T> convert) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        T[] copy = ((Object) newType == (Object) Object[].class)
                ? (T[]) new Object[newLength]
                : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        for (int i = 0; i < newLength; i++) {
            U u = original[i];
            copy[i] = convert.convert(u);
        }
        return copy;
    }

    /**
     * @param from the initial index of the range to be copied, inclusive
     * @param to   the final index of the range to be copied, exclusive.
     */
    public static <T, U> void copyOfRange(U[] original, int from, int to, T[] dest, int destFrom, CopyArrayConvert<U, T> convert) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        for (int i = 0; i < newLength; i++) {
            U u = original[i];
            dest[destFrom++] = convert.convert(u);
        }
    }

    public static <T, U> void copyOfRange(List<U> src, int from, int to, List<T> dest, int destFrom, CopyArrayConvert<U, T> convert) {
        int newLength = to - from;
        if (newLength < 0) {
            throw new IllegalArgumentException(from + " > " + to);
        }
        for (int i = from; i < to; i++) {
            U u = src.get(i);
            dest.add(destFrom + i, convert.convert(u));
        }
    }

    public static <U, T> List<T> copyOfRange(List<U> src, int from, int to, CopyArrayConvert<U, T> convert) {
        if (src == null) {
            return Collections.emptyList();
        }
        int newLength = to - from;
        if (newLength < 0) {
            throw new IllegalArgumentException(from + " > " + to);
        }
        ArrayList<T> dest = new ArrayList<>(newLength);
        for (int i = from; i < to; i++) {
            U u = src.get(i);
            dest.add(convert.convert(u));
        }
        return dest;
    }

    /**
     * @param from the initial index of the range to be copied, inclusive
     * @param to   the final index of the range to be copied, exclusive.
     */
    public static <T, U> T[] copyOfRange(List<U> original, int from, int to, Class<? extends T[]> newType, CopyArrayConvert<U, T> convert) {
        int newLength = to - from;
        if (newLength < 0)
            throw new IllegalArgumentException(from + " > " + to);
        T[] copy = ((Object) newType == (Object) Object[].class)
                ? (T[]) new Object[newLength]
                : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        for (int i = 0; i < newLength; i++) {
            U u = original.get(i);
            copy[i] = convert.convert(u);
        }
        return copy;
    }

    public interface CopyArrayConvert<U, T> {
        T convert(U u);
    }

    public interface Filter<T> {
        boolean accept(T u);
    }

}
